<?php

namespace Kiri\Server\Processes;


use Swoole\Coroutine;
use Swoole\Process;
use const SIGHUP;
use const SIGTERM;

/**
 *
 */
abstract class AbstractProcess implements OnProcessInterface
{

    private bool $stop = false;


    public Process $process;


    /**
     * @var bool
     */
    protected bool $redirect_stdin_and_stdout = FALSE;


    /**
     * @var int
     */
    protected int $pipe_type = SOCK_DGRAM;


    /**
     * @var bool
     */
    protected bool $enable_coroutine = false;


    /**
     * @var bool
     */
    protected bool $enable_queue = false;


    /**
     * @var string
     */
    public string $name = '';


    /**
     * @return bool
     */
    public function isEnableQueue(): bool
    {
        return $this->enable_queue;
    }


    /**
     * @return string
     */
    public function getName(): string
    {
        if (empty($this->name)) {
            $this->name = uniqid('p.');
        }
        return $this->name;
    }


    /**
     * @return bool
     */
    public function isStop(): bool
    {
        return $this->stop;
    }

    /**
     * @return bool
     */
    public function getRedirectStdinAndStdout(): bool
    {
        return $this->redirect_stdin_and_stdout;
    }

    /**
     * @return int
     */
    public function getPipeType(): int
    {
        return $this->pipe_type;
    }

    /**
     * @return bool
     */
    public function isEnableCoroutine(): bool
    {
        return $this->enable_coroutine;
    }


    /**
     *
     */
    public function stop(): void
    {
        $this->stop = true;
    }


    /**
     * @return void
     */
    abstract public function onSigterm(): void;


    /**
     * @param Process $process
     * @return AbstractProcess
     */
    public function onShutdown(Process $process): static
    {
        $this->process = $process;
        if ($this->enable_coroutine) {
            $array['enable_deadlock_check']        = false;
            $array['deadlock_check_disable_trace'] = false;
            $array['exit_condition']               = [$this, 'exit_condition'];
            Coroutine::set($array);
            Coroutine::create(fn() => $this->coroutineWaitSignal());
        } else {
            $process::signal(SIGTERM | SIGINT | SIGUSR1, [$this, 'pointWaitSignal']);
        }
        return $this;
    }


    public function exit_condition(): bool
    {
        return Coroutine::stats()['coroutine_num'] === 0;
    }


    /**
     * @param $signal
     * @return void
     */
    public function pointWaitSignal($signal): void
    {
        $this->stop = true;

        $this->onSigterm();
    }


    /**
     * @return void
     */
    public function coroutineWaitSignal(): void
    {
        $value = Coroutine::waitSignal(SIGTERM);
        if ($value) {
            $this->stop = true;
        }
        $this->onSigterm();
    }

}
